#pragma once

#include <memory>
#include <list>
#include <iostream>
#include <fstream>

#include "../Math/Vector.h"
#include "../Math/KernelFunction/KernelFunctionBase.h"
#include "../Network/SVM.h"

using namespace std;

class SMO
{
public:
	SMO() = delete;

	SMO(int DataDimension, int TrainningDataCount, double C, double TOL, double ESP, shared_ptr<IKernelFunctionBase> spfKernelFunction);

public:
	bool InsertTrainningData(const Vector & InputData, double ExpectValue);

	int GetInputDataDimension();

	int GetMaxTrainningDataCount();

	int GetCurrentEmptyDataIndex();

	void BeginTrain(int nMaxIterTimes);

	void SaveCSV(const char * csCSVFileName);

public:
	shared_ptr<CSVM> BuildSVM();

private:
	int TaskStep(int i1, int i2);

	int ExamineExample(int i2);

	double GetDDEValue(int il);

	double GetEValue(int il);

	bool KKTCheck(int il);

	bool KKTCheck(double E, int il);

	double Kernel(int i1, int i2);

	double SVM(int il);

	void IndexCheck(int il);

	int GetNonZandCCount();

	int GetMaxErrorIndex(int currentIndex, double Error);

	int GetRandomStartIndex(int currentIndex);

	void PickupDataToVectorCache1(int il);
	void PickupDataToVectorCache2(int il);

    double CaleDaulProblemValue();

	void SnapAlphaData(double daulValue);
    
private:
	double m_C;

	double m_TOL;

	double m_ESP;

	int m_InputDataDimension;

	int m_TrainningDataCount;

	int m_CurrentEmptyDataIndex;

	double m_Threshold;

	shared_ptr<double> m_TrainningData;

	shared_ptr<double> m_ExpectArray;

	shared_ptr<double> m_AlphaArray;

	shared_ptr<IKernelFunctionBase> m_spfKernelFunction;

	Vector m_TempVectorBuffer1;
	Vector m_TempVectorBuffer2;

	double m_SnapDaulProblem;
	shared_ptr<double> m_AlphaArraySnap;
};